package com.bytedance.danmaku.render.engine.demo.danmu.bordertext

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Shader
import android.graphics.Typeface
import android.text.TextUtils
import com.bytedance.danmaku.render.engine.control.DanmakuConfig
import com.bytedance.danmaku.render.engine.data.DanmakuData
import com.bytedance.danmaku.render.engine.demo.utils.DRAW_TYPE_GRADIENT_TEXT
import com.bytedance.danmaku.render.engine.render.draw.DrawItem
import com.bytedance.danmaku.render.engine.render.draw.IDrawItemFactory

/**
 * @Description:自定义渐变色弹幕
 * @Author yanxin
 * @Date:  2025/8/22
 */

class GradientDanmaku : DanmakuData() {
    override var drawType: Int = DRAW_TYPE_GRADIENT_TEXT

    var text: String? = null
    var textSize: Float? = null
    var textColor: Int? = null
    var typeface: Typeface? = null
    var textStrokeWidth: Float? = null
    var textStrokeColor: Int? = null
    var includeFontPadding: Boolean? = null
    var hasUnderline: Boolean = false
    var gradientColors: IntArray? = intArrayOf() //自定义颜色数组
}

class GradientDanmakuDrawItem : DrawItem<GradientDanmaku>() {
    private val mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
    private val mStrokeTextPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)
    private val mUnderlinePaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG)

    // 渐变相关变量
    private var gradient: LinearGradient? = null
    private var lastText: String? = null
    private var lastTextWidth: Float = 0f
    private var lastGradientColors: IntArray? = null
    private val gradientMatrix = Matrix()
    private var gradientTextColors = mutableListOf<Int>()
    override fun getDrawType(): Int {
        return DRAW_TYPE_GRADIENT_TEXT
    }
    override var x: Float = 0F
        set(value) {
            field = value
            updateXY()
        }

    private fun updateXY() {

    }

    override var y: Float = 0F
        set(value) {
            field = value
            updateXY()
        }
    override fun onBindData(data: GradientDanmaku) {
        data.gradientColors?.let {
            if (it.size > 1) {
                gradientTextColors=it.toMutableList()
            } else {
                //渐变色开始颜色 默认ui上橙黄色
                gradientTextColors.add(Color.parseColor("#FBAC45"))
                gradientTextColors.add(Color.parseColor("#FAF580"))
            }
        }
        mTextPaint.flags = Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG
        mUnderlinePaint.flags = Paint.ANTI_ALIAS_FLAG or Paint.DITHER_FLAG
    }

    override fun onMeasure(config: DanmakuConfig) {
        if (!TextUtils.isEmpty(data?.text)) {
            mTextPaint.textSize = data?.textSize ?: config.text.size
            width = mTextPaint.measureText(data?.text)
            val includeFontPadding = data?.includeFontPadding ?: config.text.includeFontPadding
            height = getFontHeight(includeFontPadding, mTextPaint)
        } else {
            width = 0F
            height = 0F
        }
    }

    override fun onDraw(canvas: Canvas, config: DanmakuConfig) {
        drawText(canvas, mStrokeTextPaint, mTextPaint, config)
        drawUnderline(canvas, mTextPaint, mUnderlinePaint, config)
    }

    override fun recycle() {
        super.recycle()
        mTextPaint.reset()
        mUnderlinePaint.reset()
    }

    /**
     * Canvas.drawText() is positioning the text by baseline
     */
    private fun drawText(canvas: Canvas, strokePaint: Paint, paint: Paint, config: DanmakuConfig) {
        data?.text?.let { text ->

            // draw stroke
            (data?.textStrokeWidth ?: config.text.strokeWidth).takeIf { it > 0 }?.let { width ->
                strokePaint.style = Paint.Style.STROKE
                strokePaint.color = data?.textStrokeColor ?: config.text.strokeColor
                strokePaint.typeface = data?.typeface ?: config.text.typeface
                strokePaint.textSize = data?.textSize ?: config.text.size
                strokePaint.strokeWidth = width
                val baseline = getBaseline(data?.includeFontPadding ?: true, y, strokePaint)
                canvas.drawText(text, x, baseline, strokePaint)
            }

            handleGradient(text)
            // draw drawText
            paint.style = Paint.Style.FILL
//            paint.color = data?.textColor ?: config.text.color
            paint.typeface = data?.typeface ?: config.text.typeface
            paint.textSize = data?.textSize ?: config.text.size
            paint.strokeWidth = 0f

            val includeFontPadding = data?.includeFontPadding ?: config.text.includeFontPadding
            val baseline = getBaseline(includeFontPadding, y, paint)
            canvas.drawText(text, x, baseline, paint)
        }
    }

    //todo: 优化避免每次文字移动都创建LinearGradient，每个文字创建一次其余都是根据坐标去移动
    private fun handleGradient(text: String) {
        val colors= gradientTextColors.toIntArray()
        val textWidth = mTextPaint.measureText(text)
        // 只在以下情况重新创建渐变：
        // 1. 渐变不存在
        // 2. 文字内容变化
        // 3. 文字宽度变化
        // 4. 渐变色变化
        if (gradient == null ||
            !text.contentEquals(lastText) ||
            !colors.contentEquals(lastGradientColors)
        ) {
            gradient = LinearGradient(
                0f, 0f, textWidth, 0f, // 渐变区域匹配文字宽度
                colors,
                null,
                Shader.TileMode.CLAMP
            ).apply {
                // 保存当前状态
                lastText = text
                lastTextWidth = textWidth
                lastGradientColors = colors.copyOf()
            }
        }
        // 更新渐变位置（每次绘制都执行）
        gradientMatrix.reset()
        gradientMatrix.postTranslate(x, 0f) // 根据当前x位置偏移
        gradient?.setLocalMatrix(gradientMatrix)
        mTextPaint.shader = gradient
    }

    private fun drawUnderline(
        canvas: Canvas,
        textPaint: Paint,
        underlinePaint: Paint,
        config: DanmakuConfig
    ) {
        takeIf { data?.hasUnderline == true }?.let {
            val includeFontPadding = data?.includeFontPadding ?: config.text.includeFontPadding
            val underlineY =
                y + getFontHeight(includeFontPadding, textPaint) + config.underline.marginTop
            // draw underline stroke
            takeIf { config.underline.strokeWidth > 0 }?.let {
                underlinePaint.style = Paint.Style.STROKE
                underlinePaint.color = config.underline.strokeColor
                underlinePaint.strokeWidth = config.underline.strokeWidth
                canvas.drawRect(
                    x,
                    underlineY,
                    x + width,
                    underlineY + config.underline.width,
                    underlinePaint
                )
            }
            // draw underline
            underlinePaint.style = Paint.Style.FILL
            underlinePaint.color = data?.textColor ?: config.underline.color
            underlinePaint.strokeWidth = 0f
            canvas.drawRect(
                x,
                underlineY,
                x + width,
                underlineY + config.underline.width,
                underlinePaint
            )
        }
    }

    private fun getFontHeight(includeFontPadding: Boolean, paint: Paint): Float {
        return if (includeFontPadding)
            paint.fontMetrics.bottom - paint.fontMetrics.top
        else
            paint.fontMetrics.bottom - paint.fontMetrics.ascent
    }

    private fun getBaseline(includeFontPadding: Boolean, top: Float, paint: Paint): Float {
        return if (includeFontPadding) top - paint.fontMetrics.top else top - paint.fontMetrics.ascent
    }
}

class GradientDanmakuItemFactory : IDrawItemFactory {
    override fun getDrawType(): Int {
        return DRAW_TYPE_GRADIENT_TEXT
    }

    override fun generateDrawItem(): DrawItem<out DanmakuData> {
        return GradientDanmakuDrawItem()
    }
}
